#include "socket.hpp"
#include "Log.hxx"
#include <string>
#include <vector>
#include <memory>
#include <array>
#include <sys/select.h>
#include <algorithm>
#include <sys/time.h>
using namespace Net_TcpSocket;

class SelectServer{

    
    public:
    SelectServer(int16_t port)
    :_port(port)
    ,_listenSock(new TcpSocket)
    {
        _listenSock ->BuildListenSocket(_port,default_backlog); 

    }
    void InitSelect()
    {
        for(int i = 0;i<FD_SETSIZE;i++)
        {
            _SocketFds[i] = nullptr;
        }
        int opt = 1;
        setsockopt(_listenSock->GetSockfd(),SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
        _SocketFds[_listenSock->GetSockfd()] = _listenSock;
    }
    private:
    void HandleReadEvent(const fd_set & rfds)
    {
        for(int i = 0;i<FD_SETSIZE;i++)
        {
            if(_SocketFds[i] == nullptr)
            {
                continue;
            }
            //分两类套接字
            if(_listenSock->GetSockfd() == i)
            {
                //有新连接
                std::string PeerIp;uint16_t PeerPort;
                std::shared_ptr<Socket> newSock = std::shared_ptr<Socket>(_listenSock->AcceptConnection(&PeerIp,&PeerPort));
                if(newSock == nullptr)
                {
                    myService::lg(myService::Log::Error,"accept error");
                    continue;
                }
                if(newSock->GetSockfd() >= FD_SETSIZE)
                {
                    myService::lg(myService::Log::Error,"Server Is Full\n");
                    continue;
                }
                _SocketFds[newSock->GetSockfd()] = newSock;
                myService::lg(myService::Log::Info,"accept new connection %s,%u",PeerIp.c_str(),PeerPort);
            }
            else
            {
                //普通套接字的读取事件处理
                std::string buf;
                bool ret = _SocketFds[i]->Recv(&buf,1024);
                if(ret)
                {
                    std::cout<<"recv data from client:"<<buf<<std::endl;
                }
                else
                {
                    myService::lg
                    (myService::Log::Info,"close connection %u",_SocketFds[i]->GetSockfd());
                    _SocketFds[i] = nullptr;
                }
            }
        }
    }
    public:
    void WorkLoop()
    {
        _IsRunning = true;
        while(_IsRunning)
        {
            //accept实际也是一种IO拷贝，其有新连接，相当少是读时间就绪
            fd_set rfds;
            FD_ZERO(&rfds);
            int max_fd = _listenSock->GetSockfd();
            //获取最大max_Fd,且设置rfds表
            for(int i = 0;i<FD_SETSIZE;i++)
            {
                if(_SocketFds[i] != nullptr)
                {
                    FD_SET(_SocketFds[i]->GetSockfd(),&rfds);
                    max_fd = std::max(max_fd,_SocketFds[i]->GetSockfd());
                }
            }

            PrintDebug();
            //有三种选项，设置时间0非阻塞等待
            //空指针永久等待
            //设置时间等待时间数，没收到数据就退出
            struct timeval timeout = {0,0};
            int n = select(max_fd+1,&rfds,nullptr,nullptr,nullptr);
            switch(n)
            {
                case 0:
                myService::lg(myService::Log::Info,"select timeout,last time %u，%u",timeout.tv_sec,timeout.tv_usec);
                break;
                case -1:
                myService::lg(myService::Log::Error,"select error,errno %d,errstr %s",errno,strerror(errno));
                break;
                default:
                //新的读时间就绪
                myService::lg(myService::Log::Info,"select Read Event   ");
                HandleReadEvent(rfds);
                break;
            }
        }
        _IsRunning = false;
    }
    void PrintDebug()
    {
        //打印被select管理的链接
        for(int i = 0;i<FD_SETSIZE;i++)
        {
            if(_SocketFds[i]!=nullptr)
            {
                std::cout<<"fd:"<<_SocketFds[i]->GetSockfd()<<std::endl;
            }
        }
    }
    void Stop()
    {
        _IsRunning = false;
    }
    ~SelectServer()
    {

    }
    private:
    std::shared_ptr<Socket> _listenSock;
    int16_t _port;
    bool _IsRunning;
    std::array<std::shared_ptr<Socket>,FD_SETSIZE> _SocketFds;
};